package zm.irc.ioc.classCollector;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;

import zm.irc.ioc.ApplicationContext;
import zm.irc.ioc.annotation.AutoWired;
import zm.irc.ioc.annotation.Value;
import zm.irc.ioc.pojo.WrapClass;
import zm.irc.ioc.pojo.WrapField;

public class AutoWiredFieldEnrichment implements ClassEnrichment{
    private static final Logger log = Logger.getLogger(AutoWiredFieldEnrichment.class);


    public static Set<Class<? extends Annotation>> AUTOWIRED_ANNOTATIONS;
    static{
        AUTOWIRED_ANNOTATIONS = new HashSet<>();
        AUTOWIRED_ANNOTATIONS.add(AutoWired.class);
        AUTOWIRED_ANNOTATIONS.add(Value.class);
    }

    /**
     * <pre>
     * 1. Find out all fileds whitch annotated by {@link AutoWired}
     * 2. Wrap the field add collect into {@link WrapClass#addAutoWiredField(WrapField)}
     * </pre>
     */
    @Override
    public Set<WrapClass> enrich(Set<WrapClass> originalClasses) {
        if(CollectionUtils.isEmpty(originalClasses)){
            return Collections.emptySet();
        }
        for(WrapClass wrapClass : originalClasses){
            if(wrapClass.getBeanId().endsWith("love")){
                log.info("originalClasses");
            }
            this.doEnrichment(wrapClass);
        }

        return originalClasses;
    }
    
    private void doEnrichment(WrapClass wrapClass){
        if(wrapClass == null ){
            log.warn("Target class is empty!");
            return;
        }
        Class<?> originClass = wrapClass.getOriginClass();
        if(originClass == null ){
            log.warn("Origin class is empty!");
            return;
        }

        List<Field> fields = new ArrayList<>();
        this.getDeclaredFields(originClass, fields);
       
        if(fields.size() == 0){
            return;
        }

        for(Field field : fields){
            Annotation iocAnno = this.getIocAnno(field,AUTOWIRED_ANNOTATIONS);
            if( iocAnno == null){
                continue;
            }
            

            WrapField autoWiredField = new WrapField(field, wrapClass);
            autoWiredField.setIocAnno(iocAnno);
            boolean isBeanClass = BeanClassFilter.isBeanClass(autoWiredField.getFieldClass());
            
          //  if(isBeanClass || isApplicationContext(autoWiredField.getFieldClass())){
                wrapClass.addAutoWiredField(autoWiredField);

            // }else{
            //     throw new RuntimeException("Can not find such bean: "+autoWiredField.getFieldClassName());
            // }
           
        }
    }

    private void getDeclaredFields(Class<?> clazz,List<Field> fieldList){
        if( clazz == Object.class){
            return;
        }
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            fieldList.add(field);
        }
        this.getDeclaredFields(clazz.getSuperclass(), fieldList);
    }

    private boolean isApplicationContext(WrapClass fieldCLass){
        if(fieldCLass == null){
            return false;
        }
        
        return ApplicationContext.class.equals(fieldCLass.getOriginClass());


    }

    /**
     * @param field
     * @param autoWiredAnnos
     * @return
     */
    private Annotation getIocAnno(Field field,Set<Class<? extends Annotation>> autoWiredAnnos){
        Annotation[] annos = field.getDeclaredAnnotations();
        if( annos == null || annos.length ==0){
            return null;
        }
        for(Annotation anno : annos){
            if(autoWiredAnnos.contains(anno.annotationType()) ){
                return anno;
            }
        }
        return null;
    }


}
